
from comm import Config

from utils.HttpsClient import HttpsClient
import json
from data.model.Params import *
from data.model.Trade import *

from broker.tws.constant.Constant import *

import logging
log = logging.getLogger("syslog")

class RestApi:

    def __init__(self, port: int = Config.FUTU_OPEND_PORT):
        self.port = port
        server_url = Config.PORTAL_WEB_SEVER.replace("{port}", "%s" % port)
        self.req_client = HttpsClient(server_url)

    def tickle(self) -> (RET, Tickle):
        """
        Session - Ping the server to keep the session open
        """
        tickle = None
        ret, data = self.req_client.get('/tickle')
        if ret.code == RetCode.OK:
            tickle = Tickle.parse(data)
            log.debug("Session - keep session open： %s" % tickle)
        return ret, tickle

    def auth_status(self):
        """
        Session - Current Authentication status to the Brokerage system.
        Market Data and Trading is not possible if not authenticated, e.g. authenticated shows false
        """
        data = self.req_client.post('/iserver/auth/status')
        log.debug("Session - Authentication Status： %s" % data)

    def reauthenticate(self):
        """
        Session - When using the CP Gateway, this endpoint provides a way to
        reauthenticate to the Brokerage system as long as there is a valid SSO session
        """
        data = self.req_client.post('/iserver/reauthenticate')
        log.debug("Session - Tries to re-authenticate to Brokerage： %s" % data)

    def sso_validate(self):
        """
        Session - Validates the current session for the SSO user
        """
        data = self.req_client.get('/sso/validate')
        log.debug("Session - Validate SSO： %s" % data)



    def accounts(self):
        """
        Account - Returns a list of accounts the user has trading access to, their respective aliases and the currently selected account.
        Note this endpoint must be called before modifying an order or querying open orders.
        """
        data = self.req_client.get('/iserver/accounts')
        log.debug("Account - Brokerage Accounts： %s" % data)

    def account(self, accountId:str):
        """
        Account - If an user has multiple accounts, and user wants to get orders, trades, etc.
        of an account other than currently selected account, then user can update the currently selected account
        using this API and then can fetch required information for the newly updated account.
        """
        reqdata = {"acctId": accountId}
        data = self.req_client.post('/iserver/accounts', data=reqdata)
        log.debug("Account - Switch Account： %s" % data)
        return data

    def accountSummary(self, accountId:str) -> (RET, AccountSummary):
        summary = None
        reqURL = "/portfolio/%s/summary" % accountId
        ret, data = self.req_client.get(reqURL)
        if ret.code == RetCode.OK:
            summary = AccountSummary.parse(data)
            log.debug("Account - Account Summary： %s" % summary)
        return ret, summary

    def accountLedger(self, accountId:str) -> (RET, AccountLedger):
        ledger = None
        reqURL = "/portfolio/%s/ledger" % accountId
        ret, data = self.req_client.get(reqURL)
        if ret.code == RetCode.OK:
            ledger = AccountLedger.parse(data)
            log.debug("Account - Account Ledger： %s" % data)
        return ret, ledger



    def trades(self) -> (RET, list):
        """
        Trades - Returns a list of trades for the currently selected account for current day and six previous days.
        It is advised to call this endpoint once per session.
        List of Trades for the selected account
        """
        trades = list()
        ret, data = self.req_client.get('/iserver/account/trades')
        if ret.code == RetCode.OK:
            trades = Trade.parse(data)
            tradeStrs = [str(x) for x in trades]
            log.debug("Trades - List of Trades for the selected account： %s" % tradeStrs)
        return ret, trades


    def secdef_search(self, symbol) -> (RET, Contract):
        """ Search Security by Symbol """
        cont = None
        reqdata = {"secType": "STK"}
        reqdata["symbol"] = symbol
        ret, data = self.req_client.post('/iserver/secdef/search', data=reqdata)
        if ret.code == RetCode.OK:
            cont = Contract.parse(data)
            log.debug("Contract - Search Security by Symbol： %s" % cont)
        return ret, cont



    def live_orders(self):
        """ Order - RLive Orders """
        data = self.req_client.get('/iserver/account/orders')
        log.debug("Order - Live Orders： %s" % data)

    def preview_orders(self, accountId, order: OrderReq) -> (RET, PreOrder):
        """
        preview order without actually submitting the order and you can get commission information in the response. Also supports bracket orders.
        """
        preorder = None
        reqData = {"orders": [order.to_map()]}
        reqURL = "/iserver/account/%s/orders/whatif" % accountId
        ret, data = self.req_client.post(reqURL, data=reqData)
        if ret.code == RetCode.OK:
            preorder = PreOrder.parse(data, order.price)
            log.debug("Order - Preview Orders： %s" % preorder)
        return ret, preorder

    def place_orders(self, accountId, order: OrderReq) -> (RET, POrder):
        """ Order - Place Orders """
        porder = None
        reqData = {"orders": [order.to_map()]}
        reqURL = "/iserver/account/%s/orders" % accountId
        ret, data = self.req_client.post(reqURL, data=reqData)
        if ret.code == RetCode.OK:
            porder = POrder.parse_place(data, order.price)
            log.debug("Order - Place Orders： %s" % porder)
        return ret, porder

    def reply_order(self, replyid):
        reqData = {"confirmed": True}
        reqURL = "/iserver/reply/%s" % replyid
        return self.req_client.post(reqURL, data=reqData)



    def order_status(self, orderId) -> (RET, OrderStatus):
        """ Order - Order Status """
        orderstatus = None
        reqURL = "/iserver/account/order/status/%s" % orderId
        ret, data = self.req_client.post(reqURL)
        if ret.code == RetCode.OK:
            orderstatus = OrderStatus.parse(data)
            log.debug("Order - Order Status： %s" % orderstatus)
        return ret, orderstatus

    def modify_order(self, accountId:str, orderId:str):
        """
        Order - Modify Order
        accountId   required  account id, or fa group if modifying a group order
        orderId     required  Customer order id, use /iservers/account/orders endpoint to query orderId.
        """
        "https://localhost:5000/v1/api/iserver/account/{accountId}/order/{orderId}"
        reqURL = "/iserver/account/%s/order/%s" % (accountId, orderId)
        data = self.req_client.post(reqURL, )
        log.debug("Order - Order Status： %s" % data)
        orderstatus = OrderStatus.parse(data)
        return orderstatus



    def pa_performance(self, accountId, freq:str = "D"):
        """
        PortfolioAnalyst - Account Performance
        """
        reqURL = "/pa/performance"
        params = {"acctIds": [accountId], "freq": freq}
        data = self.req_client.post(reqURL, params)
        log.debug("PortfolioAnalyst - Account Performance： %s" % data)




